Source for file SC_Query.php
Documentation is available at SC_Query.php
* This file is part of EC-CUBE
* Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
* http://www.lockon.co.jp/
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
require_once realpath(dirname(__FILE__ )) . '/../module/MDB2.php';
* TODO エラーハンドリング, ロギング方法を見直す
* @author LOCKON CO.,LTD.
* @version $Id: SC_Query.php 21284 2011-10-18 03:09:15Z Seasoft $
* @param string $dsn データソース名
* @param boolean $force_run エラーが発生しても処理を続行する場合 true
* @param boolean $new 新規に接続を行うかどうか
function SC_Query($dsn = "", $force_run = false, $new = false) {
$options['debug'] = PEAR_DB_DEBUG;
$options['persistent'] = PEAR_DB_PERSISTENT;
// バッファリング trueにするとメモリが解放されない。
$options['result_buffering'] = false;
$this->conn = MDB2::connect($dsn, $options);
$this->conn = MDB2::singleton($dsn, $options);
if (!PEAR::isError($this->conn)) {
$this->conn->setCharset("utf8");
$this->conn->setFetchMode(MDB2_FETCHMODE_ASSOC);
$this->dbFactory = SC_DB_DBFactory_Ex::getInstance();
* シングルトンの SC_Query インスタンスを取得する.
* @param string $dsn データソース名
* @param boolean $force_run エラーが発生しても処理を続行する場合 true
* @param boolean $new 新規に接続を行うかどうか
* @return SC_Query シングルトンの SC_Query インスタンス
if (!isset ($GLOBALS['_SC_Query_instance'])
|| is_null($GLOBALS['_SC_Query_instance'])) {
$GLOBALS['_SC_Query_instance'] = & new SC_Query_Ex($dsn, $force_run, $new);
$GLOBALS['_SC_Query_instance']->where = '';
$GLOBALS['_SC_Query_instance']->arrWhereVal = array();
$GLOBALS['_SC_Query_instance']->order = '';
$GLOBALS['_SC_Query_instance']->groupby = '';
$GLOBALS['_SC_Query_instance']->option = '';
return $GLOBALS['_SC_Query_instance'];
* @deprecated PEAR::isError() を使用して下さい
if(PEAR::isError($this->conn)) {
* @param string $table テーブル名
* @param string $where where句
* @param array $arrWhereVal プレースホルダ
function count($table, $where = "", $arrWhereVal = array()) {
$sqlse = "SELECT COUNT(*) FROM $table";
$sqlse = "SELECT COUNT(*) FROM $table WHERE $where";
$sqlse = $this->dbFactory->sfChangeMySQL($sqlse);
return $this->getOne($sqlse, $arrWhereVal);
* @param string $col カラム名. 複数カラムの場合はカンマ区切りで書く
* @param string $table テーブル名
* @param string $where WHERE句
* @param array $arrWhereVal プレースホルダ
* @param integer $fetchmode 使用するフェッチモード。デフォルトは MDB2_FETCHMODE_ASSOC。
function select($col, $table, $where = "", $arrWhereVal = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
$sqlse = $this->getSql($col, $table, $where, $arrWhereVal);
return $this->getAll($sqlse, $arrWhereVal, $fetchmode);
* @param boolean $disp trueの場合、画面出力を行う.
$sql = $this->conn->last_query;
* @return MDB2_OK 成功した場合は MDB2_OK;
* 失敗した場合は PEAR::Error オブジェクト
return $this->conn->commit();
* @return MDB2_OK 成功した場合は MDB2_OK;
* 失敗した場合は PEAR::Error オブジェクト
return $this->conn->beginTransaction();
* @return MDB2_OK 成功した場合は MDB2_OK;
* 失敗した場合は PEAR::Error オブジェクト
return $this->conn->rollback();
* トランザクションが開始されているかチェックする.
* @return boolean トランザクションが開始されている場合 true
return $this->conn->inTransaction();
* この関数は SC_Query::query() のエイリアスです.
* FIXME MDB2::exec() の実装であるべき
function exec($str, $arrval = array()) {
return $this->query($str, $arrval);
* クエリを実行し、結果行毎にコールバック関数を適用する
* @param callback $function コールバック先
* @param string $sql SQL クエリ
* @param array $arrVal プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
* @param integer $fetchmode 使用するフェッチモード。デフォルトは DB_FETCHMODE_ASSOC。
function doCallbackAll($cbFunc, $sql, $arrval = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
$sql = $this->dbFactory->sfChangeMySQL($sql);
$sth = & $this->prepare($sql);
if (PEAR::isError($sth) && $this->force_run) {
$affected = & $this->execute($sth, $arrval);
if (PEAR::isError($affected) && $this->force_run) {
while($data = $affected->fetchRow($fetchmode)) {
* @param string $sql SQL クエリ
* @param array $arrVal プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
* @param integer $fetchmode 使用するフェッチモード。デフォルトは DB_FETCHMODE_ASSOC。
* @return array データを含む2次元配列。失敗した場合に 0 または DB_Error オブジェクトを返します。
function getAll($sql, $arrval = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
$sql = $this->dbFactory->sfChangeMySQL($sql);
$sth = & $this->prepare($sql);
if (PEAR::isError($sth) && $this->force_run) {
$affected = & $this->execute($sth, $arrval);
if (PEAR::isError($affected) && $this->force_run) {
return $affected->fetchAll($fetchmode);
* クラス変数から WHERE 句を組み立てる場合、$arrWhereVal を経由してプレースホルダもクラス変数のもので上書きする。
* @param string $col SELECT 文に含めるカラム名
* @param string $table SELECT 文に含めるテーブル名
* @param string $where SELECT 文に含める WHERE 句
* @param mixed $arrWhereVal プレースホルダ(参照)
* @return string 構築済みの SELECT 文
function getSql($col, $table, $where = '', &$arrWhereVal = null) {
$sqlse = "SELECT $col FROM $table";
$sqlse .= " WHERE $where";
$sqlse .= " WHERE " . $this->where;
// 実行時と同じくキャストしてから評価する (空文字を要素1の配列と評価させる意図)
$arrWhereValForEval = (array) $arrWhereVal;
if (empty($arrWhereValForEval)) {
* SELECT 文の末尾に付与する SQL を設定する.
* この関数で設定した値は SC_Query::getSql() で使用されます.
* @param string $str 付与する SQL 文
* @return SC_Query 自分自身のインスタンス
* SELECT 文に付与する LIMIT, OFFSET 句を設定する.
* この関数で設定した値は SC_Query::getSql() で使用されます.
* TODO MDB2::setLimit() を使用する
* @param integer $limit LIMIT 句に付与する値
* @param integer $offset OFFSET 句に付与する値
* @return SC_Query 自分自身のインスタンス
$option = " LIMIT " . $limit;
$option.= " OFFSET " . $offset;
* SELECT 文に付与する GROUP BY 句を設定する.
* この関数で設定した値は SC_Query::getSql() で使用されます.
* @param string $str GROUP BY 句に付与する文字列
* @return SC_Query 自分自身のインスタンス
$this->groupby = "GROUP BY " . $str;
* SELECT 文の WHERE 句に付与する AND 条件を設定する.
* この関数で設定した値は SC_Query::getSql() で使用されます.
* @param string $str WHERE 句に付与する AND 条件の文字列
* @return SC_Query 自分自身のインスタンス
$this->where .= " AND " . $str;
* SELECT 文の WHERE 句に付与する OR 条件を設定する.
* この関数で設定した値は SC_Query::getSql() で使用されます.
* @param string $str WHERE 句に付与する OR 条件の文字列
* @return SC_Query 自分自身のインスタンス
$this->where .= " OR " . $str;
* SELECT 文に付与する WHERE 句を設定する.
* この関数で設定した値は SC_Query::getSql() で使用されます.
* @param string $where WHERE 句に付与する文字列
* @param mixed $arrWhereVal プレースホルダ
* @return SC_Query 自分自身のインスタンス
function setWhere($where = '', $arrWhereVal = array()) {
* SELECT 文に付与する ORDER BY 句を設定する.
* この関数で設定した値は SC_Query::getSql() で使用されます.
* @param string $str ORDER BY 句に付与する文字列
* @return SC_Query 自分自身のインスタンス
$this->order = "ORDER BY " . $str;
* SELECT 文に付与する LIMIT 句を設定する.
* この関数で設定した値は SC_Query::getSql() で使用されます.
* @param integer $limit LIMIT 句に設定する値
* @return SC_Query 自分自身のインスタンス
$this->option = " LIMIT " . $limit;
* SELECT 文に付与する OFFSET 句を設定する.
* この関数で設定した値は SC_Query::getSql() で使用されます.
* @param integer $offset LIMIT 句に設定する値
* @return SC_Query 自分自身のインスタンス
$this->offset = " OFFSET " . $offset;
* @param string $table テーブル名
* @param array $sqlval array('カラム名' => '値',...)の連想配列
function insert($table, $sqlval) {
if(count($sqlval) <= 0 ) return false;
foreach ($sqlval as $key => $val) {
} else if(strcasecmp('CURRENT_TIMESTAMP', $val) === 0) {
$strval .= 'CURRENT_TIMESTAMP,';
$sqlin = "INSERT INTO $table(" . $strcol. ") VALUES (" . $strval . ")";
$ret = $this->query($sqlin, $arrval, false, null, MDB2_PREPARE_MANIP);
* @param string $table テーブル名
* @param array $sqlval array('カラム名' => '値',...)の連想配列
* @param string $where WHERE句
* @param array $arrWhereVal WHERE句用のプレースホルダ配列 (従来は追加カラム用も兼ねていた)
* @param array $arrRawSql 追加カラム
* @param array $arrRawSqlVal 追加カラム用のプレースホルダ配列
function update($table, $sqlval, $where = "", $arrWhereVal = array(), $arrRawSql = array(), $arrRawSqlVal = array()) {
foreach ($sqlval as $key => $val) {
$arrCol[] = $key . '= Now()';
} else if(strcasecmp('CURRENT_TIMESTAMP', $val) === 0) {
$arrCol[] = $key . '= CURRENT_TIMESTAMP';
$arrCol[] = $key . '= ?';
foreach($arrRawSql as $key => $val) {
$arrCol[] = "$key = $val";
if (is_array($arrWhereVal)) { // 旧版との互換用
$sqlup = "UPDATE $table SET $strcol";
$sqlup .= " WHERE $where";
return $this->query($sqlup, $arrVal, false, null, MDB2_PREPARE_MANIP);
* @param string $table テーブル名
* @param string $col カラム名
* @param string $where 付与する WHERE 句
* @param array $arrval プレースホルダに挿入する値
* @return integer MAX文の実行結果
function max($col, $table, $where = "", $arrval = array()) {
$ret = $this->get("MAX($col)", $table, $where, $arrval);
* @param string $table テーブル名
* @param string $col カラム名
* @param string $where 付与する WHERE 句
* @param array $arrval プレースホルダに挿入する値
* @return integer MIN文の実行結果
function min($col, $table, $where = "", $arrval = array()) {
$ret = $this->get("MIN($col)", $table, $where, $arrval);
* SQL を構築して, 特定のカラムの値を取得する.
* @param string $table テーブル名
* @param string $col カラム名
* @param string $where 付与する WHERE 句
* @param array $arrWhereVal プレースホルダに挿入する値
* @return mixed SQL の実行結果
function get($col, $table, $where = "", $arrWhereVal = array()) {
$sqlse = $this->getSql($col, $table, $where, $arrWhereVal);
$ret = $this->getOne($sqlse, $arrWhereVal);
* SQL を指定して, 特定のカラムの値を取得する.
* @param string $sql 実行する SQL
* @param array $arrval プレースホルダに挿入する値
* @return mixed SQL の実行結果
function getOne($sql, $arrval = array()) {
$sql = $this->dbFactory->sfChangeMySQL($sql);
$sth = & $this->prepare($sql);
if (PEAR::isError($sth) && $this->force_run) {
$affected = & $this->execute($sth, $arrval);
if (PEAR::isError($affected) && $this->force_run) {
return $affected->fetchOne();
* @param string $table テーブル名
* @param string $col カラム名
* @param string $where WHERE句
* @param array $arrWhereVal プレースホルダ配列
* @param integer $fetchmode 使用するフェッチモード。デフォルトは MDB2_FETCHMODE_ASSOC。
* @return array array('カラム名' => '値', ...)の連想配列
function getRow($col, $table, $where = "", $arrWhereVal = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
$sql = $this->getSql($col, $table, $where, $arrWhereVal);
$sql = $this->dbFactory->sfChangeMySQL($sql);
$sth = & $this->prepare($sql);
if (PEAR::isError($sth) && $this->force_run) {
$affected = & $this->execute($sth, $arrWhereVal);
if (PEAR::isError($affected) && $this->force_run) {
return $affected->fetchRow($fetchmode);
* SELECT 文の実行結果を 1列のみ取得する.
* @param string $table テーブル名
* @param string $col カラム名
* @param string $where 付与する WHERE 句
* @param array $arrWhereVal プレースホルダに挿入する値
* @return array SQL の実行結果の配列
function getCol($col, $table, $where = "", $arrWhereVal = array()) {
$sql = $this->getSql($col, $table, $where, $arrWhereVal);
$sql = $this->dbFactory->sfChangeMySQL($sql);
$sth = & $this->prepare($sql);
if (PEAR::isError($sth) && $this->force_run) {
$affected = & $this->execute($sth, $arrWhereVal);
if (PEAR::isError($affected) && $this->force_run) {
return $affected->fetchCol();
* @param string $table テーブル名
* @param string $where WHERE句
* @param array $arrval プレースホルダ
function delete($table, $where = "", $arrval = array()) {
$sqlde = "DELETE FROM $table";
$sqlde = "DELETE FROM $table WHERE $where";
$ret = $this->query($sqlde, $arrval, false, null, MDB2_PREPARE_MANIP);
* @param string $seq_name 取得するシーケンス名
* @param integer 次のシーケンス値
return $this->conn->nextID($seq_name);
* @param string $seq_name 取得するシーケンス名
* @return integer 現在のシーケンス値
return $this->conn->currID($seq_name);
* @param string $seq_name シーケンス名
* @param integer $start 設定するシーケンス値
function setVal($seq_name, $start) {
$objManager = & $this->conn->loadModule('Manager');
$objManager->dropSequence($seq_name);
return $objManager->createSequence($seq_name, $start);
* FIXME $ignore_errが無視されるようになっているが互換性として問題が無いか確認が必要
* @param string $n 実行する SQL 文
* @param array $arr プレースホルダに挿入する値
* @param boolean $ignore_err MDB2切替で無効化されている (エラーが発生しても処理を続行する場合 true)
* @param mixed $types プレースホルダの型指定 デフォルトnull = string
* @param mixed $result_types 返値の型指定またはDML実行(MDB2_PREPARE_MANIP)
* @return array SQL の実行結果の配列
function query($n ,$arr = array(), $ignore_err = false, $types = null, $result_types = MDB2_PREPARE_RESULT ){
$n = $this->dbFactory->sfChangeMySQL($n);
$sth = & $this->prepare($n, $types, $result_types);
if (PEAR::isError($sth) && $this->force_run) {
$result = $this->execute($sth, $arr);
if (PEAR::isError($result) && $this->force_run) {
* @return array シーケンス名の配列
$objManager = & $this->conn->loadModule('Manager');
return $objManager->listSequences();
$objManager = & $this->conn->loadModule('Manager');
return $objManager->listTables();
* @param string $table テーブル名
* @return array 指定のテーブルのカラム名の配列
$objManager = & $this->conn->loadModule('Manager');
return $objManager->listTableFields($table);
* @param string $table テーブル名
* @return array 指定のテーブルのインデックス一覧
$objManager = & $this->conn->loadModule('Manager');
return $objManager->listTableIndexes($table);
* @param string $table テーブル名
* @param string $name インデックス名
* @param array $definition フィールド名など 通常のフィールド指定時は、$definition=array('fields' => array('フィールド名' => array()));
* MySQLのtext型フィールドを指定する場合は $definition['length'] = 'text_field(NNN)' が必要
$definition = $this->dbFactory->sfGetCreateIndexDefinition($table, $name, $definition);
$objManager = & $this->conn->loadModule('Manager');
return $objManager->createIndex($table, $name, $definition);
* @param string $table テーブル名
* @param string $name インデックス名
$objManager = & $this->conn->loadModule('Manager');
return $objManager->dropIndex($table, $name);
* @param string $table テーブル名
* @return array テーブル情報の配列
$objManager = & $this->conn->loadModule('Reverse');
return $objManager->tableInfo($table, NULL);
* TODO MDB2 に対応するための暫定的な措置.
* 本来であれば, MDB2::prepare() を適切に使用するべき
* @param string $val クォートを行う文字列
* @return string クォートされた文字列
return $this->conn->quote($val);
* パラメーターの連想配列から, テーブルに存在する列のみを取得する.
* @param string $table テーブル名
* @param array プレースホルダの連想配列
* @return array テーブルに存在する列のみ抽出した連想配列
foreach ($arrParams as $key => $val) {
$arrResults[$key] = $val;
* @param string $sql プリペアドステートメントを構築する SQL
* @param mixed $types プレースホルダの型指定 デフォルト null
* @param mixed $result_types 返値の型指定またはDML実行(MDB2_PREPARE_MANIP)、nullは指定無し
* @return MDB2_Statement_Common プリペアドステートメントインスタンス
function prepare($sql, $types = null, $result_types = MDB2_PREPARE_RESULT) {
$sth = & $this->conn->prepare($sql, $types, $result_types);
if (PEAR::isError($sth)) {
error_log($this->traceError($sth, $sql), 3, LOG_REALFILE);
* @param MDB2_Statement_Common プリペアドステートメントインスタンス
* @param array $arrVal プレースホルダに挿入する配列
* @return MDB2_Result 結果セットのインスタンス
function execute(&$sth, $arrVal = array()) {
$timeStart = SC_Utils_Ex::sfMicrotimeFloat();
$affected = & $sth->execute((array) $arrVal);
// 一定以上時間かかったSQLの場合、ログ出力する。
if(defined('SQL_QUERY_LOG_MODE') && SQL_QUERY_LOG_MODE == true) {
$timeEnd = SC_Utils_Ex::sfMicrotimeFloat();;
$timeExecTime = $timeEnd - $timeStart;
if(defined('SQL_QUERY_LOG_MIN_EXEC_TIME') && $timeExecTime >= (float) SQL_QUERY_LOG_MIN_EXEC_TIME) {
$logMsg = sprintf("SQL_LOG [%.2fsec]\n%s", $timeExecTime, $sth->query);
if (PEAR::isError($affected)) {
$sql = isset ($sth->query) ? $sth->query : '';
trigger_error($this->traceError($affected, $sql, $arrVal), E_USER_ERROR);
error_log($this->traceError($affected, $sql, $arrVal), 3, LOG_REALFILE);
* @param PEAR::Error $error PEAR::Error インスタンス
* @param string $sql エラーの発生した SQL 文
* @param array $arrVal プレースホルダ
* @return string トレースしたエラー文字列
function traceError($error, $sql = "", $arrVal = false) {
if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
$err = $scheme . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . "\n\n"
. "SERVER_ADDR: " . $_SERVER['SERVER_ADDR'] . "\n"
. "REMOTE_ADDR: " . $_SERVER['REMOTE_ADDR'] . "\n"
. "USER_AGENT: " . $_SERVER['HTTP_USER_AGENT'] . "\n\n"
. "SQL: " . $sql . "\n\n";
$err .= "PlaceHolder: " . var_export($arrVal, true) . "\n\n";
$err .= $error->getMessage() . "\n\n";
$err .= $error->getUserInfo() . "\n\n";
$err .= SC_Utils_Ex::sfBacktraceToString($error->getBackTrace());
* SQLクエリの結果セットのカラム名だけを取得する
* @param string $n 実行する SQL 文
* @param array $arr プレースホルダに挿入する値
* @param boolean エラーが発生しても処理を続行する場合 true
* @param mixed $types プレースホルダの型指定 デフォルトnull = string
* @param mixed $result_types 返値の型指定またはDML実行(MDB2_PREPARE_MANIP)
function getQueryDefsFields($n ,$arr = array(), $ignore_err = false, $types = null, $result_types = MDB2_PREPARE_RESULT ){
$n = $this->dbFactory->sfChangeMySQL($n);
$sth = & $this->prepare($n, $types, $result_types);
if (PEAR::isError($sth) && ($this->force_run || $ignore_err)) {
$result = $this->execute($sth, $arr);
if (PEAR::isError($result) && ($this->force_run || $ignore_err)) {
$arrRet = $result->getColumnNames();
Documentation generated on Fri, 24 Feb 2012 14:02:54 +0900 by Seasoft
|